#include "libs/NMEAParser.cpp"

//---------------------------------------------------------------------------
// DataSource
//---------------------------------------------------------------------------
LOCALCLASSBASE( DataSource, public MVPositionSource )
    CNMEAParser parser;
    bool        Active;
    MyString    DataStr;

  public:
    DataSource( PMVDataHandler h );
    virtual ~DataSource();

    virtual bool         IsFix( void );
    virtual PosSrcState  GetState( void );
    virtual void         GetTime( PRTime& tm );
    virtual void         GetInfo( MVPosInfo& tm );
    virtual int          SatsUsed( void );
    virtual int          SatCount( void );
    virtual bool         SatItem( int idx, MVSatInfo& si );

    virtual bool         Initialize( PHConfigItem cfg );
    virtual void         WorkSlice( void );
    virtual void         Stop( void );
};

//---------------------------------------------------------------------------
//  DataSource
//---------------------------------------------------------------------------
DataSource::DataSource( PMVDataHandler h )
    : MVPositionSource(h)
  {
     Active = false;
}

DataSource::~DataSource()
  {
    parser.Reset();
}

int  DataSource::SatsUsed( void ) { return parser.m_btGGANumOfSatsInUse; }
int  DataSource::SatCount( void ) { return parser.m_wGSVTotalNumSatsInView; }
bool DataSource::IsFix( void )    {  PosSrcState s = GetState(); return s == pssFix2d || s == pssFix3d; }

PosSrcState DataSource::GetState( void )
  {
     if ( !Active || !Handler->IsActive() )
       return pssNotConnect;

     switch( parser.m_btGSAFixMode ) {
       case 1: return pssNoFix;
       case 2: return pssFix2d;
       case 3: return pssFix3d;
     }
 return pssNotConnect;
}

void DataSource::GetInfo( MVPosInfo& pi )
  {
     pi.Datum = WGS84_Datum_Index;

     if ( parser.m_dwRMCCount ) {
       pi.x = parser.m_dRMCLongitude;
       pi.y = parser.m_dRMCLatitude;
     } else
     if ( parser.m_dwGGACount ) {
       pi.x = parser.m_dGGALongitude;
       pi.y = parser.m_dGGALatitude;
     } else {
       pi.x = 0;
       pi.y = 0;
     }

     if ( parser.m_dwGGACount ) {
       pi.Altitude    = parser.m_dGGAAltitude;
       pi.VertSpeed   = parser.m_dGGAVertSpeed;
     } else {
       pi.Altitude    = UNKNOWN_ALTITUDE;
       pi.VertSpeed   = 0;
     }

     if ( parser.m_dwRMCCount ) {
       pi.Speed  = parser.m_dRMCGroundSpeed;
       pi.Course = parser.m_dRMCCourse;
     } else {
       pi.Speed  = 0;
       pi.Course = UNKNOWN_DIR;
     }

     if ( parser.m_dwGSACount ) {
       pi.PDop = parser.m_dGSAPDOP;
       pi.HDop = parser.m_dGSAHDOP;
       pi.VDop = parser.m_dGSAVDOP;
     } else
     if ( parser.m_dwGGACount ) {
       pi.PDop = 0;
       pi.HDop = parser.m_dGGAHDOP;
       pi.VDop = 0;
     } else {
       pi.PDop = 0;
       pi.HDop = 0;
       pi.VDop = 0;
     }
}

void DataSource::GetTime( PRTime& tm )
  {
     if ( parser.m_dwZDACount ) {
       tm.year = parser.m_wZDAYear;
       tm.mon  = parser.m_btZDAMonth;
       tm.mday = parser.m_btZDADay;
       tm.hour = parser.m_btZDAHour;
       tm.min  = parser.m_btZDAMinute;
       tm.sec  = parser.m_btZDASecond;
     } else
     if ( parser.m_dwRMCCount ) {
       tm.year = parser.m_wRMCYear;
       tm.mon  = parser.m_btRMCMonth;
       tm.mday = parser.m_btRMCDay;
       tm.hour = parser.m_btRMCHour;
       tm.min  = parser.m_btRMCMinute;
       tm.sec  = parser.m_btRMCSecond;
     } else
     if ( parser.m_dwGGACount ) {
       tm.Set( time(NULL) );

       tm.hour = parser.m_btGGAHour;
       tm.min  = parser.m_btGGAMinute;
       tm.sec  = parser.m_btGGASecond;
     } else
       tm.Zero();
}

bool DataSource::SatItem( int idx, MVSatInfo& si)
  {
     if ( idx < 0 || idx >= SatCount() )
       return false;

     si.Valid     = parser.m_GSVSatInfo[idx].m_bUsedInSolution;
     si.Index     = parser.m_GSVSatInfo[idx].m_wPRN;
     si.Quality   = parser.m_GSVSatInfo[idx].m_wSignalQuality;
     si.Azimuth   = parser.m_GSVSatInfo[idx].m_wAzimuth;
     si.Elevation = parser.m_GSVSatInfo[idx].m_wElevation;

 return true;
}

void DataSource::WorkSlice( void )
  {
     if ( !Active )
       return;

     DWORD b = GetTickCount(), e;
     while( 1 ) {
       e = GetTickCount();
       if ( e-b > 100 ) return;

       BYTE ch;
       if ( !Handler->Read( &ch,1 ) ) {
         if ( Handler->IsEOF() )
           Stop();
         return;
       }
       DataStr.Add( (char)ch );

       DWORD c    = parser.m_dwCommandCount,
             cpos = parser.m_dwGGACount + parser.m_dwRMCCount;
       parser.ProcessNMEA( ch );

       if ( c != parser.m_dwCommandCount ) {
         idOnNewCommand( DataStr.Text() );
         DataStr = "";
       }

       if ( cpos != parser.m_dwGGACount+parser.m_dwRMCCount )
         idOnNewPosition();
     }
}

void DataSource::Stop( void )
  {
     if ( !Active ) return;

     parser.Reset();
     Active = false;
}

bool DataSource::Initialize( PHConfigItem cfg )
  {
     if ( !Handler || !Handler->IsActive() ) {
       SetError( LNG("Associated handler is not set or inactive") );
       return false;
     }
     parser.Reset();
     Active = true;
 return true;
}
